#ifndef SPEED_CNTR_H
#define SPEED_CNTR_H

#include "user_global.h"
#include "freq_table.h"


/*--------------------Z Motor-----------------------------*/
// Z方向电机
#define IO_Z_DIR(act)                       HAL_GPIO_WritePin(CW_GPIO_Port, CW_Pin,(FlagStatus)act)
// 电机使能 1为失能 0为使能
#define IO_Z_ENABLE(act)                    HAL_GPIO_WritePin(EN_GPIO_Port, EN_Pin, (FlagStatus)!act)

#define IO_Z_M1(act)                        HAL_GPIO_WritePin(M1_GPIO_Port, M1_Pin, (FlagStatus)act)
#define IO_Z_M2(act)                        HAL_GPIO_WritePin(M2_GPIO_Port, M2_Pin, (FlagStatus)act)
#define IO_Z_M3(act)                        HAL_GPIO_WritePin(M3_GPIO_Port, M3_Pin, (FlagStatus)act)
#define IO_Z_PFD(act);                      HAL_GPIO_WritePin(LOCK_GPIO_Port, LOCK_Pin, (FlagStatus)act)


#define IO_Z_HOME                           !HAL_GPIO_ReadPin(Z_RESET_GPIO_Port,Z_RESET_Pin)
#define Z_AT_HOME                           IO_Z_HOME
#define DRAW_AT_CLOSE                       IO_Z_HOME

#define IO_Z_LIMIT                          !HAL_GPIO_ReadPin(Z_LIMIT_GPIO_Port,Z_LIMIT_Pin)
#define Z_AT_LIMIT                          IO_Z_LIMIT
#define DRAW_AT_OPEN                        IO_Z_LIMIT

struct SpeedRampData;

typedef void (*SPEED_CALLBACK)(uchar role);
typedef void (*STEP_UPDATE)(uchar role);
typedef void (*PULSE_PROC)(uchar role,uchar level);
typedef void (*TIMER_PROC)(uchar role);
typedef void (*STOP_TIMER)(uchar role);
typedef void (*SRD_PROC)(struct SpeedRampData *srd);


typedef struct SpeedRampData
{
    uchar run_state : 3;        // What part of the speed ramp we are in.
    uchar dir : 1;              // Direction stepper motor should move.
    uchar running : 1;          // 电机正在运行
    uchar need_cleanup : 1;     // 需要运行清除函数
    uchar home_state : 1;       // 原点传感器状态
    uchar limit_state :1;
    uchar limit_state2 :1;
    uchar limit_state3 :1;
    uchar hit_home : 1;         // 运行经过原点
    uchar hit_limit : 1;        // 运行经过原点
    uchar hit_limit2 : 1;       // 运行经过原点
    uchar hit_limit3 : 1;       // 运行经过原点
    uchar coder_self : 1;       // 脉冲计数方式 0：编码器计数 1：定时器自身计数

    ushort speed_index;         // Counter used when accelerateing/decelerateing to calculate step_delay.
    ushort max_index;           // 频率表最大索引
    long step_left;             // 电机剩余运行步数
    ulong step_count;           // Counting steps when moving.
    ulong start_time;           // 开始运行时间
    signed char step_offset;    // 每走一步的增量, +/-1
    long target;                // 目标坐标
    long max_target;            // 最大目标坐标
    uchar micro;                // 当前电机细分, 为0时表示使用默认16细分
    ushort first_stage_speed;   // 开始阶段低速运行的速度索引
    ushort first_stage_step;    // 开始阶段低速运行的步数
    ushort second_stage_speed;  // 结束阶段低速运行的速度索引
    ushort second_stage_step;   // 结束阶段低速运行的步数

    ulong stamp;
    long pos;                   // 运动前的初始位置
    uchar role;                 // 当前电机属性名
    uchar micro_step;           // 细分脉冲计步步数
    long reset_step;            // 电机运行时感应到复位传感器后的缓冲步数
    long limit_step;            // 电机运行时感应到限位传感器后的缓冲步数
    long limit2_step;           // 电机运行时感应到限位传感器后的缓冲步数
    long limit3_step;           // 电机运行时感应到限位传感器后的缓冲步数
    long limit_target;          // 电机运行时的最大目标位置

    SPEED_CALLBACK init;        // 电机启动前调用的初始化函数
    SPEED_CALLBACK update;      // 每走一步调用的函数
    SPEED_CALLBACK cleanup;     // 停止后调用的函数
    PULSE_PROC step;            // step信号输出
    TIMER_PROC start_timer;     // 更新定时器
    STOP_TIMER stop_timer;      // 停止定时器
} SpeedRampData;

typedef struct SRD_DESC
{
    uint32_t timer;
    uint16_t timer_ch;
    uchar home;                      // 表示复位光耦,对应 GPIO_IN 中的传感器 ID值
    uchar limit;                     // 表示限位光耦,对应 GPIO_IN 中的传感器 ID值
    uchar limit2;                    // 表示限位光耦,对应 GPIO_IN 中的传感器 ID值
    uchar limit3;                    // 表示限位光耦,对应 GPIO_IN 中的传感器 ID值
    SpeedRampData *srd;
} SRD_DESC;

extern SRD_DESC srd_desc[MACHINE_COUNT];

// 执行动作定义
enum ACTION
{
    STANDBY = 0000,                            // 取消当前执行动作.
    MRESET,                                    // 复位. 所有部件复位到原点位置
    SELFTEST,                                  // 自检. 执行一次自检动作，自检动作完成后，
                                               // 更新相关标志位和设备状态,
    TRANS_IN,                                  // 推入电机S1/S2从输入缓冲区推入样本架到传送带输入区,
                                               // 然后传送带传送试管架到输出区到位位置
                                               // [\*->IMPORT->EXPORT]
                                               // ACTION_ARG[0]为传送参数
                                               // - D15:2 保留，为0
                                               // - D1 扫码标志
                                               //   - 为0 表示传送过程中进行扫码
                                               //   - 为1 表示传送过程中不进行扫码
                                               // - D0 选择使用左右推入电机
                                               //   - 为0 表示使用左推入电机S1从左缓冲区推入
                                               //   - 为1 表示使用右推入电机S2从右缓冲区推入
    T1_TRANS_OUT,                              // T1 传送带传送试管架从轨道输出区，传送到下一单元输入口
                                               // [EXPORT->\*]
                                               // ACTION_ARG[0]为传送参数
                                               // - D15:2 保留，为0
                                               // - D1 扫码标志
                                               //   - 为0 表示传送过程中进行扫码
                                               //   - 为1 表示传送过程中不进行扫码
                                               // - D0 为0
    S_T1_TRANS_IN_OUT,                         // 推入电机S1/S2从输入缓冲区推入样本架到传送带输入区,
                                               // 然后T1传送带传送试管架从轨道输出区，传送到下一单元输入口
                                               // [\*->IMPORT->EXPORT->\*]
                                               // ACTION_ARG[0]为传送参数
                                               // - D15:2 保留，为0
                                               // - D1 扫码标志
                                               //   - 为0 表示传送过程中进行扫码
                                               //   - 为1 表示传送过程中不进行扫码
                                               // - D0 选择使用左右推入电机
                                               //   - 为0 表示使用左推入电机S1从左缓冲区推入
                                               //   - 为1 表示使用右推入电机S2从右缓冲区推入
    TRANS_NEXT_STATION,
    S_PUSH_RACKS_TO_IMPORT,                    // 推入电机S1/S2从输入缓冲区推送样本架传送带输入
                                               // 位置[\*->IMPORT]
                                               // ACTION_ARG[0]为传送参数
                                               // - D15:1 保留，为0
                                               // - D0 选择使用左右推入电机
                                               //   - 为0 表示使用左推入电机S1从左缓冲区推入
                                               //   - 为1 表示使用右推入电机S2从右缓冲区推入
    T1_TRANS_TO_TARGET,                        // T1传送带电机传送到目标位置,step
                                               // | ACTION_ARG[0]为目标位置高16位,
                                               // | ACTION_ARG[1]为目标位置低16位,
                                               // | ACTION_ARG[2]为最大运行速度
    OPEN_BUFL_GATE,                            // 打开左缓冲输入节点闸门
    CLOSE_BUFL_GATE,                           // 关闭左缓冲输入节点闸门
    OPEN_BUFR_GATE,                            // 打开右缓冲输入节点闸门
    CLOSE_BUFR_GATE,                           // 关闭右缓冲输入节点闸门
    OPEN_EXPORT_GATE,                          // 打开输出区节点闸门
    CLOSE_EXPORT_GATE,                         // 关闭输出区节点闸门
    HOME_S1,                                   // 复位 S1 ,然后只将 S1 移动到光耦遮挡位置.
                                               // 如果, S1 已经在遮挡位置,S1 无动作
    HOME_S2,                                   // 复位 S2 ,然后只将 S2 移动到光耦遮挡位置.
                                               // 如果, S2 已经在遮挡位置,S2 无动作
    HOME_V1,                                   // 复位 V1 ,然后只将 V1 移动到光耦遮挡位置.
                                               // 如果, V1 已经在遮挡位置,V1 无动作
    HOME_V2,                                   // 复位 V2 ,然后只将 V2 移动到光耦遮挡位置.
                                               // 如果, V2 已经在遮挡位置,V2 无动作
    HOME_V3,                                   // 复位 V3 ,然后只将 V3 移动到光耦遮挡位置.
                                               // 如果, V3 已经在遮挡位置,V3 无动作
    DISABLE_MOTOR,                             // 解锁所有电机

};

// 状态定义
enum MACHINE_STATUS
{
    EXEC_STATUS_CONDITIONS_ERROR = 1,
    RACK_STATUS_READY_IMPORTL_ERROR,    // 0002 未检测到轨道左输入区试管架到位
    RACK_STATUS_READY_IMPORTR_ERROR,    // 0003 未检测到轨道右输入区试管架到位
    RACK_STATUS_READY_EXPORT_ERROR,     // 0004 未检测到轨道输出口试管架到位
    S1_STATUS_HOME_SENSOR_ERROR,        // 0005 S1复位传感器故障. 1: 故障 0: 正常
    S2_STATUS_HOME_SENSOR_ERROR,        // 0005 S2复位传感器故障. 1: 故障 0: 正常
    V1_STATUS_HOME_SENSOR_ERROR,        // 0006 V1复位传感器故障. 1: 故障 0: 正常
    V2_STATUS_HOME_SENSOR_ERROR,        // 0007 V2复位传感器故障. 1: 故障 0: 正常
    V3_STATUS_HOME_SENSOR_ERROR,        // 0008 V2复位传感器故障. 1: 故障 0: 正常
    S1_STATUS_LIMIT_SENSOR_ERROR,       // 0009 S1限位传感器故障. 1: 故障 0: 正常
    S2_STATUS_LIMIT_SENSOR_ERROR,       // 000A S2限位传感器故障. 1: 故障 0: 正常
    S1_STATUS_BUFFER_SENSOR_ERROR,      // 000B S1限位传感器故障. 1: 故障 0: 正常
    S2_STATUS_BUFFER_SENSOR_ERROR,      // 000C S2限位传感器故障. 1: 故障 0: 正常
    S1_STATUS_MOTOR_ERROR,              // 000D S1电机故障. 1: 故障 0: 正常
    S2_STATUS_MOTOR_ERROR,              // 000E S1电机故障. 1: 故障 0: 正常
    V1_STATUS_MOTOR_ERROR,              // 000F V1电机故障. 1: 故障 0: 正常
    V2_STATUS_MOTOR_ERROR,              // 0010 V2电机故障. 1: 故障 0: 正常
    V3_STATUS_MOTOR_ERROR,              // 0011 V2电机故障. 1: 故障 0: 正常
    T1_STATUS_MACHANSIM_ERROR,          // 0012 T1传送机构故障. 1: 故障 0: 正常
    SCANNER_STATUS_ERROR,               // 0013 扫码器故障. 1: 故障 0: 正常
};

// Speed ramp states
#define MOTION_STATE_STOP       0
#define MOTION_STATE_ACCEL      1
#define MOTION_STATE_DECEL      2
#define MOTION_STATE_RUN        3

#define CCW                     0   // 反向
#define CW                      1   // 正向

extern SpeedRampData srd[MACHINE_COUNT];

void speed_cntr_Move(SpeedRampData *srd, long step, unsigned int speed);
void speed_update(uchar role);
void Move_To_Update(uchar role);
void InitMachine(void);
void Set_Timer(uchar role);
void Stop_Timer(uchar role);
void Step(uchar role,uchar level);
void Do_Action_Move_To(uchar role, long target, ushort speed);
void Do_Action_T_Trans_To_Target(uchar role,long target,ushort speed);
void Do_Action_Home(void);
void Do_Action_T1_Trans_Out(void);
void Do_Action_Stop(uchar role);
void Do_Action_Reset_NoWait(uchar role);

#define SPEED2INDEX(speed)      (ushort)((ulong)(speed) * (speed) * ( 1 / (2 * ALPHA * ACCEL * 100)))
#define DISTANCE2STEP(d)        (ushort)((d) / Z_PERIMETER * SPR)

#endif
